package com.gzc.just.play.last.war.sceneserver.sight;

import com.gzc.just.play.last.war.sceneserver.gameobject.base.GameObjectCamp;
import com.gzc.just.play.last.war.sceneserver.gameobject.base.Position;
import com.gzc.just.play.last.war.sceneserver.gameobject.unit.GameUnit;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 视野管理器 - 管理单位的视野范围和可见性
 *
 * 功能：
 * - 计算单位的视野范围
 * - 检查目标是否可见
 * - 获取视野范围内的单位列表
 * - 处理视野变化事件
 *
 * 对应C++的 SSight 视野系统
 *
 * @author AI编程助手
 * @version 1.0
 * @since 2025-11-22
 */
public class SightManager {
    
    private static final Logger log = LoggerFactory.getLogger(SightManager.class);
    
    // 默认视野范围（单位: 坐标单位）
    private static final float DEFAULT_HERO_SIGHT_RANGE = 200.0f;
    private static final float DEFAULT_MINION_SIGHT_RANGE = 120.0f;
    private static final float DEFAULT_BUILDING_SIGHT_RANGE = 150.0f;
    
    // 所有可见的单位映射
    private final Map<Long, GameUnit> visibleUnits = new HashMap<>();
    private final Map<Long, Long> visibilityTime = new HashMap<>(); // 最后可见时间
    
    private final GameUnit observer;
    private float customSightRange = -1; // -1表示使用默认值
    private final List<SightListener> listeners = new CopyOnWriteArrayList<>();
    
    /**
     * 创建视野管理器
     *
     * @param observer 观察者（拥有视野的单位）
     */
    public SightManager(GameUnit observer) {
        this.observer = observer;
    }
    
    /**
     * 获取视野范围
     *
     * @return 视野范围（坐标单位）
     */
    public float getSightRange() {
        if (customSightRange > 0) {
            return customSightRange;
        }
        
        // 根据单位类型返回默认视野
        switch (observer.getObjectType()) {
            case HERO:
                return DEFAULT_HERO_SIGHT_RANGE;
            case SOLDIER:
                return DEFAULT_MINION_SIGHT_RANGE;
            case BUILDING:
                return DEFAULT_BUILDING_SIGHT_RANGE;
            default:
                return DEFAULT_HERO_SIGHT_RANGE;
        }
    }
    
    /**
     * 设置自定义视野范围
     *
     * @param range 视野范围，-1表示恢复使用默认值
     */
    public void setSightRange(float range) {
        this.customSightRange = range;
        log.debug("设置视野范围: {}", range);
    }
    
    /**
     * 检查目标是否在视野范围内
     *
     * @param target 目标单位
     * @return 如果在视野范围内，返回true
     */
    public boolean isInSight(GameUnit target) {
        if (target == null || target == observer) {
            return false;
        }
        
        if (!target.isActive()) {
            return false;
        }
        
        // 检查距离
        Position observerPos = observer.getPosition();
        Position targetPos = target.getPosition();
        
        if (observerPos == null || targetPos == null) {
            return false;
        }
        
        double distance = observerPos.distance(targetPos);
        return distance <= getSightRange();
    }
    
    /**
     * 获取视野范围内的所有单位
     *
     * @param allUnits 游戏中的所有单位列表
     * @return 可见单位列表
     */
    public List<GameUnit> getVisibleUnits(List<GameUnit> allUnits) {
        List<GameUnit> visible = new ArrayList<>();
        
        for (GameUnit unit : allUnits) {
            if (isInSight(unit)) {
                visible.add(unit);
            }
        }
        
        return visible;
    }
    
    /**
     * 记录可见单位
     *
     * @param unit 可见的单位
     */
    public void onUnitVisible(GameUnit unit) {
        if (unit == null) {
            return;
        }
        
        long unitId = unit.getObjectId();
        long currentTime = System.currentTimeMillis();
        
        if (!visibleUnits.containsKey(unitId)) {
            visibleUnits.put(unitId, unit);
            visibilityTime.put(unitId, currentTime);
            log.debug("单位进入视野: {}", unitId);
            notifySightChanged(unit, true);
        } else {
            visibilityTime.put(unitId, currentTime);
        }
    }
    
    /**
     * 记录不可见单位
     *
     * @param unit 不可见的单位
     */
    public void onUnitOutOfSight(GameUnit unit) {
        if (unit == null) {
            return;
        }
        
        long unitId = unit.getObjectId();
        
        if (visibleUnits.remove(unitId) != null) {
            visibilityTime.remove(unitId);
            log.debug("单位离开视野: {}", unitId);
            notifySightChanged(unit, false);
        }
    }
    
    /**
     * 更新视野（检查单位是否进入/离开视野）
     *
     * @param allUnits 游戏中的所有单位
     */
    public void updateSight(List<GameUnit> allUnits) {
        Set<Long> currentVisibleIds = new HashSet<>();
        
        // 检查新进入视野的单位
        for (GameUnit unit : allUnits) {
            if (isInSight(unit)) {
                long unitId = unit.getObjectId();
                currentVisibleIds.add(unitId);
                onUnitVisible(unit);
            }
        }
        
        // 检查离开视野的单位
        List<Long> toRemove = new ArrayList<>();
        for (Long unitId : visibleUnits.keySet()) {
            if (!currentVisibleIds.contains(unitId)) {
                toRemove.add(unitId);
            }
        }
        
        for (Long unitId : toRemove) {
            GameUnit unit = visibleUnits.get(unitId);
            if (unit != null) {
                onUnitOutOfSight(unit);
            }
        }
    }
    
    /**
     * 获取可见的单位数量
     */
    public int getVisibleUnitCount() {
        return visibleUnits.size();
    }
    
    /**
     * 获取所有可见的单位
     */
    public Collection<GameUnit> getVisibleUnits() {
        return new ArrayList<>(visibleUnits.values());
    }
    
    /**
     * 检查是否可见某个单位
     *
     * @param unitId 单位ID
     */
    public boolean isUnitVisible(long unitId) {
        return visibleUnits.containsKey(unitId);
    }
    
    /**
     * 清除所有可见单位
     */
    public void clearVisibleUnits() {
        visibleUnits.clear();
        visibilityTime.clear();
        log.debug("清除所有可见单位");
    }
    
    /**
     * 添加视野变化监听器
     */
    public void addListener(SightListener listener) {
        if (listener != null) {
            listeners.add(listener);
        }
    }
    
    /**
     * 移除视野变化监听器
     */
    public void removeListener(SightListener listener) {
        listeners.remove(listener);
    }
    
    /**
     * 通知视野变化
     */
    private void notifySightChanged(GameUnit unit, boolean visible) {
        for (SightListener listener : listeners) {
            try {
                if (visible) {
                    listener.onUnitEnteredSight(observer, unit);
                } else {
                    listener.onUnitLeftSight(observer, unit);
                }
            } catch (Exception e) {
                log.error("视野变化监听器异常", e);
            }
        }
    }
    
    /**
     * 获取可见单位的列表（按距离排序）
     *
     * @return 按距离从近到远排列的可见单位列表
     */
    public List<GameUnit> getVisibleUnitsSorted() {
        List<GameUnit> units = new ArrayList<>(visibleUnits.values());
        
        Position observerPos = observer.getPosition();
        if (observerPos == null) {
            return units;
        }
        
        // 按距离排序
        units.sort((u1, u2) -> {
            Position p1 = u1.getPosition();
            Position p2 = u2.getPosition();
            
            if (p1 == null) return 1;
            if (p2 == null) return -1;
            
            double dist1 = observerPos.distance(p1);
            double dist2 = observerPos.distance(p2);
            
            return Double.compare(dist1, dist2);
        });
        
        return units;
    }
    
    /**
     * 获取最近的可见敌人
     *
     * @param allUnits 所有单位列表（用于检查敌友）
     * @return 最近的敌人，如果没有返回null
     */
    public GameUnit getNearestVisibleEnemy(List<GameUnit> allUnits) {
        double minDistance = Double.MAX_VALUE;
        GameUnit nearest = null;
        
        Position observerPos = observer.getPosition();
        if (observerPos == null) {
            return null;
        }
        
        for (GameUnit unit : getVisibleUnits()) {
            if (isEnemy(unit)) {
                Position targetPos = unit.getPosition();
                if (targetPos != null) {
                    double distance = observerPos.distance(targetPos);
                    if (distance < minDistance) {
                        minDistance = distance;
                        nearest = unit;
                    }
                }
            }
        }
        
        return nearest;
    }
    
    /**
     * 检查两个单位是否为敌人
     */
    private boolean isEnemy(GameUnit unit) {
        return observer.getCamp() != null && unit.getCamp() != null &&
               GameObjectCamp.isEnemy(observer.getCamp(), unit.getCamp());
    }
    
    /**
     * 获取视野摘要信息
     */
    public String getSightSummary() {
        return String.format("视野范围: %.1f, 可见单位: %d",
            getSightRange(), getVisibleUnitCount());
    }
}
